package com.weimob.mcloud.wechatwork.customer.third.core;

import com.alibaba.dubbo.config.annotation.Reference;
import com.google.common.collect.Lists;
import com.google.common.collect.Maps;
import com.weimob.mcloud.wechatwork.core.base.MultiResponse;
import com.weimob.mcloud.wechatwork.core.base.SingleRequest;
import com.weimob.mcloud.wechatwork.core.constant.CustomerCoreConstant;
import com.weimob.mcloud.wechatwork.core.entity.privatesphere.PrivateSphere;
import com.weimob.mcloud.wechatwork.core.entity.relation.CustomerEmployeeRelation;
import com.weimob.mcloud.wechatwork.core.entity.relation.customer.Customer;
import com.weimob.mcloud.wechatwork.core.entity.relation.employee.Employee;
import com.weimob.mcloud.wechatwork.core.enums.customer.CustomerStatusEnum;
import com.weimob.mcloud.wechatwork.core.enums.customer.ExternalUserTypeEnum;
import com.weimob.mcloud.wechatwork.core.service.customer.CustomerService;
import com.weimob.mcloud.wechatwork.core.service.customer.request.CusEmpRelationScrollRequest;
import com.weimob.mcloud.wechatwork.core.service.customer.request.CustomerByIdsRequest;
import com.weimob.mcloud.wechatwork.core.service.customer.response.CusEmpRelationScrollResponse;
import com.weimob.mcloud.wechatwork.core.util.CustomerEmployeeRelationSplitUtil;
import com.weimob.mcloud.wechatwork.statistics.exception.BizException;
import com.weimob.soa.common.response.SoaResponse;
import com.weimob.soa.common.utils.SoaUtil;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.collections.CollectionUtils;
import org.apache.commons.collections.MapUtils;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Component;

import java.util.*;

/**
 * @author chenliuzhu
 * @date 2022/12/19
 */
@Component
@Slf4j
public class CustomerServiceProxy {

    @Reference
    CustomerService customerService;

    @Value("${cus.emp.relation.scroll.pagesize:100}")
    private Integer scrollPageSize;

    @Value("${customer.ids.handler.partitioncount:10}")
    private Integer partitionCount;

    @Value("${customer.employee.relation.switch.read:true}")
    private boolean readTableFlag;

    public List<Customer> fetchCustomerByIds(List<String> customersIds, List<String> externalUserIds, PrivateSphere privateSphere) {
        return fetchCustomerByIds(customersIds, externalUserIds, privateSphere, false, null, null);
    }

    public List<Customer> fetchCustomerByIds(List<String> customersIds, List<String> externalUserIds, PrivateSphere privateSphere, ExternalUserTypeEnum externalUserType) {
        return fetchCustomerByIds(customersIds, externalUserIds, privateSphere, false, externalUserType, null);
    }

    public List<Customer> fetchCustomerByIds(List<String> customersIds, List<String> externalUserIds, PrivateSphere privateSphere, boolean fetchCustomerDetail) {
        return fetchCustomerByIds(customersIds, externalUserIds, privateSphere, fetchCustomerDetail, null, null);
    }

    public List<Customer> fetchCustomerByIds(List<String> customersIds, List<String> externalUserIds, PrivateSphere privateSphere, CustomerStatusEnum status) {
        return fetchCustomerByIds(customersIds, externalUserIds, privateSphere, false, null, status);
    }

    public List<Customer> fetchCustomerByIds(List<String> customersIds, List<String> externalUserIds, PrivateSphere privateSphere, boolean fetchCustomerDetail, ExternalUserTypeEnum externalUserType, CustomerStatusEnum status) {
        CustomerByIdsRequest customerByIdsRequest = new CustomerByIdsRequest();
        customerByIdsRequest.setCustomerIds(customersIds);
        customerByIdsRequest.setExternalUserids(externalUserIds);
        Customer customer = new Customer();
        customer.setPrivateSphere(privateSphere);
        customer.setExternalUserType(externalUserType);
        customer.setStatus(status);
        customerByIdsRequest.setCustomer(customer);
        customerByIdsRequest.setFetchCustomerDetail(fetchCustomerDetail);
        return SoaUtil.unpack(customerService.fetchCustomerByIds(customerByIdsRequest));
    }


    public List<Customer> fetchCustomerByIds(List<String> externalUserIds, PrivateSphere privateSphere, Integer status, Boolean fetchCustomerDetail) {
        CustomerByIdsRequest customerByIdsRequest = new CustomerByIdsRequest();
        customerByIdsRequest.setExternalUserids(externalUserIds);
        Customer customer = new Customer();
        customer.setPrivateSphere(privateSphere);
        if (status != null) {
            customer.setStatus(CustomerStatusEnum.getEnumByCode(status));
        }
        customerByIdsRequest.setCustomer(customer);
        customerByIdsRequest.setFetchCustomerDetail(fetchCustomerDetail);

        return SoaUtil.unpack(customerService.fetchCustomerByIds(customerByIdsRequest));
    }

    public List<Customer> fetchCustomerByIds(String customerId, String externalUserId, PrivateSphere privateSphere) {
        return fetchCustomerByIds(customerId, externalUserId, privateSphere, null);
    }

    public List<Customer> fetchCustomerByIds(String customerId, String externalUserId, PrivateSphere privateSphere, ExternalUserTypeEnum externalUserType) {
        CustomerByIdsRequest customerByIdsRequest = new CustomerByIdsRequest();
        Customer customerReq = new Customer();
        customerReq.setId(customerId);
        customerReq.setPrivateSphere(privateSphere);
        customerReq.setExternalUserid(externalUserId);
        customerReq.setExternalUserType(externalUserType);

        customerByIdsRequest.setCustomer(customerReq);
        return SoaUtil.unpack(customerService.fetchCustomerByIds(customerByIdsRequest));
    }


    public Customer fetchCustomer(String customerId, String externalUserId, PrivateSphere privateSphere) {

        return fetchCustomer(customerId, externalUserId, privateSphere, null);
    }

    public Customer fetchCustomer(String customerId, String externalUserId, PrivateSphere privateSphere, ExternalUserTypeEnum externalUserType) {

        SingleRequest<Customer> customerSingleRequest = new SingleRequest<>();

        Customer customerReq = new Customer();
        customerReq.setId(customerId);
        customerReq.setPrivateSphere(privateSphere);
        customerReq.setExternalUserid(externalUserId);
        customerReq.setExternalUserType(externalUserType);

        customerSingleRequest.setData(customerReq);
        try {
            MultiResponse<Customer> unpack = SoaUtil.unpack(customerService.fetchCustomer(customerSingleRequest));
            if (CollectionUtils.isEmpty(unpack.getDataList())) {
                return null;
            }
            return unpack.getDataList().get(0);
        } catch (Exception e) {
            log.error("fetchCustomer error: ", e);
            return null;
        }

    }


    public MultiResponse<CustomerEmployeeRelation> fetchCustomerEmployeeRelationPage(String customerId, String employeeId, PrivateSphere privateSphere,
                                                                                     Boolean fetchGuider, CustomerStatusEnum status, Boolean friended,
                                                                                     Integer pageNum, Integer pageSize) {
        CustomerEmployeeRelation customerEmpRelRequest = new CustomerEmployeeRelation();
        customerEmpRelRequest.setPrivateSphere(privateSphere);
        customerEmpRelRequest.setCustomerId(customerId);
        customerEmpRelRequest.setFriended(friended);

        if (!StringUtils.isEmpty(employeeId)) {
            Employee employee = new Employee();
            employee.setId(employeeId);
            customerEmpRelRequest.setEmployee(employee);
        }

        customerEmpRelRequest.setStatus(status);
        SingleRequest<CustomerEmployeeRelation> request = new SingleRequest<>(customerEmpRelRequest, pageNum, pageSize);
        request.setPrivateSphere(privateSphere);
        Map<String, Object> map = new HashMap<>();
        if (null != fetchGuider) {
            map.put(CustomerCoreConstant.FETCH_GUIDER, fetchGuider);
        }
        request.setExtInfo(map);

        return SoaUtil.unpack(customerService.fetchCustomerEmployeeRelation(request));
    }


    public List<CustomerEmployeeRelation> fetchCustomerEmployeeRelation(String customerId, String employeeId, PrivateSphere privateSphere,
                                                                        CustomerStatusEnum status, Boolean friended, Boolean fetchGuider) {
        CustomerEmployeeRelation customerEmployeeRelation = new CustomerEmployeeRelation();
        customerEmployeeRelation.setPrivateSphere(privateSphere);
        customerEmployeeRelation.setCustomerId(customerId);

        if (StringUtils.isNotBlank(employeeId)) {
            Employee employee = new Employee();
            employee.setId(employeeId);
            customerEmployeeRelation.setEmployee(employee);
        }

        customerEmployeeRelation.setFriended(friended);
        customerEmployeeRelation.setStatus(status);
        SingleRequest<CustomerEmployeeRelation> request = new SingleRequest<>(customerEmployeeRelation);
        Map<String, Object> map = new HashMap<>();
        if (null != fetchGuider) {
            map.put(CustomerCoreConstant.FETCH_GUIDER, fetchGuider);
        }
        request.setPrivateSphere(privateSphere);
        request.setExtInfo(map);


        return fetchCustomerEmployeeRelation(request);
    }

    public List<CustomerEmployeeRelation> fetchCustomerEmployeeRelation(List<String> customerIds, String employeeId, PrivateSphere privateSphere,
                                                                        CustomerStatusEnum status) {
        CustomerEmployeeRelation customerEmployeeRelation = new CustomerEmployeeRelation();
        customerEmployeeRelation.setPrivateSphere(privateSphere);
        if (StringUtils.isNotEmpty(employeeId)) {
            Employee employee = new Employee();
            employee.setId(employeeId);
            customerEmployeeRelation.setEmployee(employee);
        }
        customerEmployeeRelation.setStatus(status);
        SingleRequest<CustomerEmployeeRelation> request = new SingleRequest<>(customerEmployeeRelation);
        request.setPrivateSphere(privateSphere);
        if (CollectionUtils.isNotEmpty(customerIds)) {
            HashMap<String, Object> extInfoMap = Maps.newHashMap();
            extInfoMap.put(CustomerCoreConstant.CUSTOMER_IDS, customerIds);
            request.setExtInfo(extInfoMap);
        }
        return fetchCustomerEmployeeRelation(request);
    }

    /**
     * 查询客户员工关系
     *
     * @param request request
     * @return
     */
    private List<CustomerEmployeeRelation> fetchCustomerEmployeeRelation(SingleRequest<CustomerEmployeeRelation> request) {
        SoaResponse<MultiResponse<CustomerEmployeeRelation>, ?> soaResponse = customerService.fetchCustomerEmployeeRelation(request);
        if (!SoaUtil.isSucc(soaResponse)) {
            throw new BizException(soaResponse.getReturnMsg());
        }
        MultiResponse<CustomerEmployeeRelation> responseVo = soaResponse.getResponseVo();
        if (Objects.isNull(responseVo)) {
            return Collections.emptyList();
        }
        return responseVo.getDataList();
    }

    /**
     * 查询客户有几个员工关系
     *
     * @param corpId
     * @param customerId
     * @param friend
     * @param status
     * @return
     */
    public Long fetchCustomerEmployeeRelationCount(String corpId, String customerId, Boolean
            friend, CustomerStatusEnum status) {

        CustomerEmployeeRelation customerEmployeeRelation = new CustomerEmployeeRelation();

        customerEmployeeRelation.setCorpId(corpId);
        customerEmployeeRelation.setCustomerId(customerId);
        customerEmployeeRelation.setFriended(friend);
        customerEmployeeRelation.setStatus(status);
        try {
            Long count = SoaUtil.unpack(customerService.fetchCustomerEmployeeRelationCount(customerEmployeeRelation));
            if (count == null) {
                return 0L;
            }
            return count;
        } catch (Exception e) {
            log.error("fetchCustomerEmployeeRelationCount 异常 error: ", e);
            return 0L;
        }
    }


    /**
     * 滚动查询关系数据
     *
     * @param employeeIds 员工ids
     * @param corpId      corpId
     * @param nextId      游标
     * @return
     */
    public CusEmpRelationScrollResponse scrollRelationByEmpIds(List<String> employeeIds, String corpId, CustomerStatusEnum statusEnum, Long nextId) {
        CusEmpRelationScrollRequest scrollRequest = new CusEmpRelationScrollRequest();
        scrollRequest.setOrgUserIds(new HashSet<>(employeeIds));
        scrollRequest.setCorpid(corpId);
        if (Objects.nonNull(statusEnum)) {
            scrollRequest.setStatus(statusEnum.getCode());
        }
        scrollRequest.setNextId(nextId);
        scrollRequest.setPageSize(scrollPageSize);
        SoaResponse<CusEmpRelationScrollResponse, ?> scrollResponseSoaResponse = customerService.scrollCustomerEmployeeRelation(scrollRequest);
        if (!SoaUtil.isSucc(scrollResponseSoaResponse) || Objects.isNull(scrollResponseSoaResponse.getResponseVo())) {
            log.error("soaResponse#scrollCustomerEmployeeRelation 未查询到数据 ,req:{}:", employeeIds);
            return null;
        }
        return scrollResponseSoaResponse.getResponseVo();
    }


    public List<CustomerEmployeeRelation> scrollRelationByEmpIds(List<String> employeeIdList, String corpId, CustomerStatusEnum statusEnum) {
        if (readTableFlag) {
            //滚动查询，获取所有的当前员工ids对应的客户员工关系数据
            return this.scrollRelationByEmpIdsV1(employeeIdList, corpId, statusEnum);
        } else {
            return this.scrollRelationByEmpIdsV2(employeeIdList, corpId, statusEnum);
        }
    }

    /**
     * 获取所有的关系数据
     *
     * @param employeeIdList
     * @param corpId
     * @return
     */
    public List<CustomerEmployeeRelation> scrollRelationByEmpIdsV2(List<String> employeeIdList, String corpId, CustomerStatusEnum statusEnum) {
        Map<Integer, List<String>> map = CustomerEmployeeRelationSplitUtil.groupEmployeeIds(employeeIdList);
        if (MapUtils.isEmpty(map)) {
            return Collections.emptyList();
        }
        List<CustomerEmployeeRelation> relationList = new ArrayList<>();
        map.forEach((shardingIndex, empIds) -> {
            List<CustomerEmployeeRelation> dataList;
            long nextId = 0L;
            do {
                //滚动查询员工的关系数据
                CusEmpRelationScrollResponse scrollResponse = scrollRelationByEmpIds(empIds, corpId, statusEnum, nextId);
                if (Objects.isNull(scrollResponse) || CollectionUtils.isEmpty(scrollResponse.getDataList())) {
                    break;
                }
                dataList = scrollResponse.getDataList();
                CustomerEmployeeRelation customerEmployeeRelation = dataList.get(dataList.size() - 1);
                //滚动游标赋值
                nextId = Long.parseLong(customerEmployeeRelation.getId());
                relationList.addAll(dataList);
            } while (dataList.size() >= scrollPageSize);
        });
        return relationList;
    }


    /**
     * 获取所有的关系数据
     *
     * @param employeeIdList
     * @param corpId
     * @return
     */
    public List<CustomerEmployeeRelation> scrollRelationByEmpIdsV1(List<String> employeeIdList, String corpId, CustomerStatusEnum statusEnum) {
        List<List<String>> empIdsPartition = Lists.partition(employeeIdList, partitionCount);
        List<CustomerEmployeeRelation> relationList = new ArrayList<>();
        List<CustomerEmployeeRelation> dataList;
        for (List<String> employeeIdsItem : empIdsPartition) {
            long nextId = 0L;
            do {
                //滚动查询员工的关系数据
                CusEmpRelationScrollResponse scrollResponse = this.scrollRelationByEmpIds(employeeIdsItem, corpId, statusEnum, nextId);
                if (Objects.isNull(scrollResponse) || CollectionUtils.isEmpty(scrollResponse.getDataList())) {
                    break;
                }
                dataList = scrollResponse.getDataList();
                CustomerEmployeeRelation customerEmployeeRelation = dataList.get(dataList.size() - 1);
                //滚动游标赋值
                nextId = Long.parseLong(customerEmployeeRelation.getId());
                relationList.addAll(dataList);
            } while (dataList.size() >= scrollPageSize);
        }
        return relationList;
    }

}
